package cn.wolfcode.shop.seckill.mq;

import cn.wolfcode.cloud.redis.RedisService;
import cn.wolfcode.shop.seckill.redis.SeckillKeyPrefix;
import cn.wolfcode.shop.seckill.result.SeckillGoodServerCodeMsg;
import cn.wolfcode.shop.seckill.service.ISeckillGoodService;
import cn.wolfcode.shop.seckill.service.ISeckillOrderService;
import cn.wolfcode.shop.seckill.vo.SeckillGoodVo;
import cn.wolfcode.shop.seckill.web.frontend.SeckillOrderController;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@Component
//@Configuration  --> 底层就是一个Conponent
public class OrderMQListener {

    @Autowired
    private ISeckillGoodService seckillGoodService;

    @Autowired
    private ISeckillOrderService seckillOrderService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisService redisService;

    @Bean //创建一个bean对象 创建一个延时队列
    public org.springframework.amqp.core.Queue orderDelayQueue(){
        Map<String,Object> map=new HashMap<>();
        map.put("x-dead-letter-exchange",MQConstants.DELAY_EXCHANGE);// 到期之后的消息的转发的交换机
        map.put("x-dead-letter-routing-key",MQConstants.ORDER_DELAY_KEY); //消息的路由key
        map.put("x-message-ttl",1000*60*30); //设置队列的相关参数: 消息的有效时间
        return new org.springframework.amqp.core.Queue(MQConstants.ORDER_RESULT_SUCCESS_DELAY_QUEUE,true,false,false,map);
    }

    @Bean //创建一个绑定关系
    public Binding bind2Delay(org.springframework.amqp.core.Queue orderDelayQueue){
        return  BindingBuilder.bind(orderDelayQueue).//构建者 的方法  队列
                to(new TopicExchange(MQConstants.ORDER_RESULT_EXCHANGE))//交换机 topic
                .with(MQConstants.ORDER_RESULT_SUCCESS_KEY); //路由key
    }

    @RabbitListener(queuesToDeclare = @Queue(MQConstants.ORDER_PEDDING_QUEUE))
    public void handlerOrderPenddingQueue(@Payload OrderMessage orderMessage, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel) throws Exception {
        Map<String, Object> hashMap = new HashMap<>();
        hashMap.put("uuid",orderMessage.getUuid());
        hashMap.put("goodId",orderMessage.getGoodId());
        try {
            SeckillGoodVo seckillGoodVo = seckillGoodService.findById(orderMessage.getGoodId());
            String orderNo = seckillOrderService.doSeckill(seckillGoodVo,orderMessage.getUserId());
            //发送成功的消息到延时队列
            hashMap.put("code",200);
            hashMap.put("orderNo",orderNo);
            rabbitTemplate.convertAndSend(MQConstants.ORDER_RESULT_EXCHANGE,MQConstants.ORDER_RESULT_SUCCESS_KEY,hashMap);
        } catch (Exception e) {
            hashMap.put("code", SeckillGoodServerCodeMsg.SECKILL_ERROR.getCode());
            hashMap.put("msg", SeckillGoodServerCodeMsg.SECKILL_ERROR.getMsg());
            //往失败队列存放  发送创建失败的队列消息
            rabbitTemplate.convertAndSend(MQConstants.ORDER_RESULT_EXCHANGE,MQConstants.ORDER_RESULT_FAIL_KEY,hashMap);
            e.printStackTrace();
        } finally {
            channel.basicAck(deliveryTag,false);

        }
    }

    @RabbitListener(bindings =@QueueBinding(
           value =@Queue(MQConstants.ORDER_RESULT_FAIL_QUEUE),
           exchange = @Exchange(name = MQConstants.ORDER_RESULT_EXCHANGE,type="topic"),
            key =MQConstants.ORDER_RESULT_FAIL_KEY
    ))
    public void  handlerOrderResultFailQueue(@Payload Long goodId, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel) throws Exception{
        try {
            //回补预库存
            seckillGoodService.synStock(goodId);
            /*redisService.incr(SeckillKeyPrefix.SECKILLGOODSTOCK,goodId+"");*/
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            channel.basicAck(deliveryTag,false);
        }
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(MQConstants.ORDER_TIMEOUT_QUEUE),
            exchange = @Exchange(name =MQConstants.DELAY_EXCHANGE,type ="topic"),
            key=MQConstants.ORDER_DELAY_KEY
    ))
    public void handlerTimeOutQueue(@Payload Map<String,Object>map, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel) throws Exception{
        try {
            Long goodId = (Long) map.get("goodId");
            String orderNo = (String) map.get("orderNo");
            int status = seckillOrderService.updateStatus(orderNo);
            //回补预库存
            if (status > 0) {
                seckillGoodService.synStock(goodId);
                /*redisService.incr(SeckillKeyPrefix.SECKILLGOODSTOCK,goodId+"");*/
                //回补数据库库存
                seckillGoodService.incr(goodId);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            channel.basicAck(deliveryTag,false);
        }
    }


    @RabbitListener(bindings=@QueueBinding(
            value = @Queue(),
            exchange = @Exchange(name=MQConstants.SECKILL_OVER_SIGN_PUBSUB_EX,type="fanout")
    ))
    public void handlerCancelSing(@Payload Long goodId, @Header(AmqpHeaders.DELIVERY_TAG)  long deliveryTag, Channel channel){
        SeckillOrderController.lock.put(goodId,false);
    }

}
